﻿#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <ctype.h>
//#include "wrap.h"
#define MAXLINE 80
#define SERVER_PORT 8888
//定义一个线程函数，用于处理select获取的socket连接。
void * get_connection(void *connection);

int main(void)
{
	pid_t pid;
	pthread_t tid;
	sigset_t sigset;
	struct sigaction newact, oldact;
	struct sockaddr_in server_addr, client_addr;
	socklen_t client_addr_len;
	int listenfd, connectfd;
	int i, n, maxi, maxfd, nready, client[FD_SETSIZE];
	fd_set rset, allset;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN];

	//设置socket
	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	//清空地址结构
	bzero(&server_addr, sizeof(server_addr));
	//初始化地址结构
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_port = htons(SERVER_PORT);
	//将地址与socket绑定
	bind(listenfd,(struct sockaddr *)&server_addr,        sizeof(server_addr));

	//设置最大监听数量
	listen(listenfd, 20);

	printf("Accepting connections ...\n");

	maxfd = listenfd;
	maxi = -1;
	for(i = 0; i< FD_SETSIZE; i++)
	{
		client[i] = -1;
	}
	//将allset清零，表示allset里没有任何可用的连接
	FD_ZERO(&allset);

	//将listened设置到allset，表示要监听该连接，当listenfd上有连接请求时将allset里的相应位置一
	FD_SET(listenfd, &allset);

	//开始循环，不停的去监视是否有连接。
	while(1)
	{
		//将allset赋值给rset，allset用于每次循环时初始化rset
		//FD_ZERO(&rset)
		//FD_SET(listenfd,&rset)
		//使用上面代码效果一样
		rset = allset;
		//使用slect进行异步监听连接，当有连接请求时在rset上相应位置一，select的返回值为select接受的连接的个数
		nready = select(maxfd+1, &rset, NULL, NULL, NULL);
		if(nready <= 0)
		{
			printf("get nothing");
		}
		//如果listenfd在rset上的相应位置一说明有客户端发起请求。
		if(FD_ISSET(listenfd, &rset))
		{
			client_addr_len = sizeof(client_addr);
			//接受一个新的连接
			connectfd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len);
			perror("list");
			//将可用的连接存入client数组。
			for(i = 0; i< FD_SETSIZE; i++)
			{
				if(client[i] < 0)
				{
					client[i] = connectfd;
					break;
				}
			}
			//如果i等于FD_SETSIZE，说明已经到达可以存放的连接的最大值。
			if(i == FD_SETSIZE)
			{
				fputs("too many clients\n",stderr);
				exit(1);
			}
			//将connectfd加入到监听序列。
			FD_SET(connectfd, &allset);
			//如果connectfd大于需要监听的最大值，则将connectfd设置为监听的最大值。
			if(connectfd > maxfd)
				maxfd= connectfd;
			//设置client数组中已经存储连接的最大数组下标。
			if(i > maxi)
				maxi = i;
			//如果--nready后为0，说明只有一个可用连接，可以返回继续监听。
			if(--nready == 0)
				continue;
		}

		//循环处理可用的连接
		for(i = 0; i <= maxi; i++)
		{
			//如果client[i]是-1，说明该值下没有存储可用的连接。
			if((connectfd = client[i]) < 0)
				continue;
			//如果connectfd是可用的连接，则创建一个线程来处理该请求。
			if(FD_ISSET(connectfd, &rset))
			{
				pthread_create(&tid, NULL, get_connection, &connectfd);
				//将该连接清除出集合。
				FD_CLR(connectfd, &allset);
				//将client数组中存储connectfd连接的相应位置为-1，以用来存储后来的连接。
				client[i] = -1;
				//如果没有剩余的连接返回。
				if(--nready == 0)
					break;
			}
		}
	}
	return 0;
}

void * get_connection(void *connection)
{
	int connect, n;
	char buf[MAXLINE];
	connect = *((int*)connection);
	printf("%d---%d\n",connect,*((int*)connection));
	while((n = read(connect, buf, MAXLINE)) != 0)
	{
		int j;
		for( j = 0; j< n; j++)
		{
			buf[j] = toupper(buf[j]);
		}
		write(connect, buf, n);
	}
	close(connect);
	return NULL;
}
